/*****************************************************************************/
/*****************************************************************************/
/* tcp.h                                                                     */
/*                                                                           */
/* Public declarations for the user-space TCP stack.                         */
/*                                                                           */
/* Note that the structures defined here are mainly hacked from the Linux    */
/* kernel. To avoid name clashes, modified structures have u_ prepended to   */
/* their name.                                                               */
/*                                                                           */
/* When structures are modified in fake-linux.h, THEY MUST BE MODIFIED       */
/* HERE ALSO!!!!!                                                            */
/*                                                                           */
/* Copyright (c) 1999, K A Fraser                                            */
/*****************************************************************************/
/*****************************************************************************/
/* Sections of this file require the following:
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 */

#ifndef __USER_TCP_H
#define __USER_TCP_H

#include "defines.h"
/*
 * XXX KAF: ix86 dependent!!
 */
#define __LITTLE_ENDIAN_BITFIELD

#include <linux/types.h>
typedef __u32 u32;
typedef __u16 u16;
typedef __u8  u8;

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define PCB_FROM_SOCKET(sk) \
    (struct user_pcb *)(((char*)(sk)) - offsetof(struct user_pcb, sock))

#ifdef USE_PTH
#include <pth.h>
#endif 

#include "pth_defs.h" 

#include <linux/bitops.h>

#ifdef USE_PTH
#include <asm/atomic.h>    // XXXX -- probably fake these to NOPs
#else
#include <./ipv4/atomic.h> 
// #include </users/manpreet/work/ibm-summer-03/ultcp/daytona/user-tcp/ipv4/atomic.h> 
#endif 

#define u_atomic_t atomic_t

//#include <net/snmp.h>
extern struct ip_mib    ip_statistics;
extern struct linux_mib net_statistics;
extern struct tcp_mib   tcp_statistics;
extern struct icmp_mib icmp_statistics;

typedef struct cache_block_st cache_block_t;
struct cache_block_st { cache_block_t *nb; };
typedef struct free_item_st free_item_t;
struct free_item_st { free_item_t *nf; };
typedef struct { int size; free_item_t *fl; cache_block_t *fb; } kmem_cache_t;

extern kmem_cache_t *__kmem_cache_create(int size);
extern void *__kmem_cache_alloc(kmem_cache_t *cache);
extern void __kmem_cache_free(kmem_cache_t *cache, void *p);
extern void __kmem_cache_destroy(kmem_cache_t *cache);


/*
 * KAF (16/12/99): it seems unlikely that timeouts are going to matter to us
 * much -- if we have to rely on them at all then we're obviously f**ked!
 * Duplicate ACKs should get us out of any scrapes, and anyway: Linux clamps
 * RTT estimates to a minimum of 200ms. (duh!)
 * 
 * Therefore we only check for timer events every (COARSE_TIMEOUT_PERIOD) ms.
 * This is very similar to BSD Reno's approach, except its period is 200ms.
 * 
 * If this is unacceptable we could increase HZ (the clock tick frequency 
 * used by the stack from 100 to something more reasonable (eg. 1000000)).
 * However, the 'jiffies' variable would have to be something more than
 * 32 bits in that case. Too much hassle right now!
 */
#define COARSE_TIMEOUT_PERIOD 50
void process_tcp_timers(void);

typedef struct {} u_spinlock_t;
#define u_spin_lock_init(a) 0
typedef struct {} u_rwlock_t;

#ifdef USE_PTH
typedef pth_cond_t /*struct {}*/ u_wait_queue_head_t;
#else
typedef int /*struct {}*/ u_wait_queue_head_t;
#endif

#define init_waitqueue_head(a) 0
typedef struct u_poll_table_struct {} u_poll_table;
struct u_scm_cookie;
struct u_file;
struct u_net_device;
struct u_dst_entry;

#ifdef USE_PTH
typedef struct {
    pth_mutex_t         m;
    unsigned int	users;
} u_socket_lock_t;
#else
typedef struct{
  unsigned int users; 
} u_socket_lock_t; 
#endif

#ifdef USE_PTH
#define bh_lock_sock(__sk) pth_mutex_acquire(&((__sk)->lock.m),0,NULL)
#define bh_unlock_sock(__sk) pth_mutex_release(&((__sk)->lock.m))
#else
#define bh_lock_sock(__sk)
#define bh_unlock_sock(__sk)
#endif

/*
 * Just enough of the sock structure to get us the remote binding, and
 * linked list chaff.
 */
struct u_sock 
{
    __u32	  daddr, rcv_saddr;
    __u16	  dport;
    u_short       num;
    int		  bound_dev_if;
    struct sock	 *next;
    struct sock	**pprev;
    struct sock	 *bind_next;
    struct sock	**bind_pprev;
    u_char        state, zapped;	
    __u16         sport;	
    u_short       family;	
    u_char        reuse, nonagle;
    atomic_t      refcnt;	

    u_socket_lock_t lock;
    struct u_sock *lprev, *lnext;
};


struct u_socket
{
  int		        state;
  unsigned long       flags;
  struct u_sock      *sk;
  u_wait_queue_head_t	wait;
  short		type;
  struct multipath_pcb* mpcb;
};

struct u_sk_buff_head {
	struct u_sk_buff * next;
	struct u_sk_buff * prev;

	__u32		qlen;
        u_spinlock_t      lock;
};

struct tcphdr {
	__u16	source;
	__u16	dest;
	__u32	seq;
	__u32	ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u16	res1:4,
		doff:4,
		fin:1,
		syn:1,
		rst:1,
		psh:1,
		ack:1,
		urg:1,
		res2:2;
#elif defined(__BIG_ENDIAN_BITFIELD)
	__u16	doff:4,
		res1:4,
		res2:2,
		urg:1,
		ack:1,
		psh:1,
		rst:1,
		syn:1,
		fin:1;
#else
#error	"Adjust your <asm/byteorder.h> defines"
#endif	
	__u16	window;
	__u16	check;
	__u16	urg_ptr;
};

struct udphdr {
	__u16	source;
	__u16	dest;
	__u16	len;
	__u16	check;
};

struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u8	ihl:4,
		version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
	__u8	version:4,
  		ihl:4;
#else
#error	"Please fix <asm/byteorder.h>"
#endif
	__u8	tos;
	__u16	tot_len;
	__u16	id;
	__u16	frag_off;
	__u8	ttl;
	__u8	protocol;
	__u16	check;
	__u32	saddr;
	__u32	daddr;
	/*The options start here. */
}; 

struct u_sk_buff {
    /* These two members must be first. */
    struct u_sk_buff *next;		/* Next buffer in list 	*/
    struct u_sk_buff *prev;		/* Previous buffer in list */

    struct u_sk_buff_head *list;		/* List we are on	*/
    struct u_sock	  *sk;			/* Socket we are owned by */
    struct u_sock         *data_sk; /* Socket the data fields owned by */
    struct u_net_device *dev;	
    struct u_net_device *rx_dev;

    /* Transport layer header */
    union
    {
        struct tcphdr   *th;
        struct udphdr   *uh;
        //struct icmphdr  *icmph;
        unsigned char   *raw;
    } h;

    /* Network layer header */
    union
    {
        struct iphdr  *iph;
        unsigned char *raw;
    } nh;
  
    /* Link layer header */
    union 
    {	
        //struct ethhdr *ethernet;
        unsigned char *raw;
    } mac;

    struct  u_dst_entry *dst;
    
    char	cb[56];	 
    
    unsigned int 	len;	/* Length of actual data*/
    unsigned int	csum;	/* Checksum 		*/
    volatile char 	used;	/* Data moved to user and not MSG_PEEK */
    unsigned char	cloned, /* head may be cloned (check refcnt to be s).*/
        pkt_type,		/* Packet class		*/
        ip_summed,		/* Driver fed us an IP checksum	*/
        rx_buf;                 /* This is received data (KAF NEW) */
    __u32 priority;             /* Packet queuing priority */
    u_atomic_t	users;	        /* User count - see datagram.c,tcp.c 	*/

    unsigned short  protocol;   /* Packet protocol from driver.*/
    unsigned int    truesize;	/* Buffer size 		*/

    u_char *d_head, *d_data, *d_tail, *d_end;
    u_char *h_head, *h_data, *h_tail, *h_end;;

    void (*destructor)(struct u_sk_buff *);
};

extern void			__kfree_skb(struct u_sk_buff *skb);
extern __inline__ void kfree_skb(struct u_sk_buff *skb)
{
	if (atomic_dec_and_test(&skb->users))
		__kfree_skb(skb);
}

extern __inline__ atomic_t *skb_datarefp(struct u_sk_buff *skb)
{
	return (u_atomic_t *)(skb->d_end);
}

extern __inline__ void skb_queue_head_init(struct u_sk_buff_head *list)
{
	u_spin_lock_init(&list->lock);
	list->prev = (struct u_sk_buff *)list;
	list->next = (struct u_sk_buff *)list;
	list->qlen = 0;
}

/*
 *	Insert an sk_buff at the end of a list.
 */
extern __inline__ void skb_queue_tail(struct u_sk_buff_head *list, 
                                      struct u_sk_buff *newsk)
{
	struct u_sk_buff *prev, *next;

	newsk->list = list;
	list->qlen++;
	next = (struct u_sk_buff *)list;
	prev = next->prev;
	newsk->next = next;
	newsk->prev = prev;
	next->prev = newsk;
	prev->next = newsk;
}

/*
 *	Remove an sk_buff from a list.
 */
extern __inline__ struct u_sk_buff *skb_dequeue(struct u_sk_buff_head *list)
{
	struct u_sk_buff *next, *prev, *result;

	prev = (struct u_sk_buff *) list;
	next = prev->next;
	result = NULL;
	if (next != prev) {
		result = next;
		next = next->next;
		list->qlen--;
		next->prev = prev;
		prev->next = next;
		result->next = NULL;
		result->prev = NULL;
		result->list = NULL;
	}
	return result;
}

/*
 *	Insert a packet on a list.
 */
extern __inline__ void skb_insert(struct u_sk_buff *newsk,
	struct u_sk_buff * prev, struct u_sk_buff *next,
	struct u_sk_buff_head * list)
{
	newsk->next = next;
	newsk->prev = prev;
	next->prev = newsk;
	prev->next = newsk;
	newsk->list = list;
	list->qlen++;
}

/*
 * remove sk_buff from list. _Must_ be called atomically, and with
 * the list known..
 */
extern __inline__ void skb_unlink(struct u_sk_buff *skb, 
                                  struct u_sk_buff_head *list)
{
	struct u_sk_buff * next, * prev;

	list->qlen--;
	next = skb->next;
	prev = skb->prev;
	skb->next = NULL;
	skb->prev = NULL;
	skb->list = NULL;
	next->prev = prev;
	prev->next = next;
}


/*
 * The maximum header size we should allow for. Includes Ethernet,
 * IP (+ options), and TCP/UDP (+ options).
 */
#define MAX_HEADER_LEN 176

/*****************************************************************************/
/* The actual public access points follow....                                */
/* (mainly from net/inet_common.h)                                           */
/*****************************************************************************/

extern void inet_proto_init(void *);
extern void inet_proto_shutdown(void);
extern int inet_create(struct u_socket *sock, int protocol);
extern int inet_bind(struct u_socket *sock, 
                     struct sockaddr *uaddr, 
                     int addr_len);
extern int inet_accept(struct u_socket *sock, 
                       struct u_socket **newsock, /* KAF changed 13/12/99 */ 
                       int flags);
extern int inet_listen(struct u_socket *sock, int backlog);
extern void			inet_remove_sock(struct u_sock *sk1);
extern void			inet_put_sock(unsigned short num, 
					      struct u_sock *sk);
extern int			inet_release(struct u_socket *sock);
extern int			inet_stream_connect(struct u_socket *sock,
						    struct sockaddr * uaddr,
						    int addr_len, int flags);
extern int			inet_dgram_connect(struct u_socket *sock, 
						   struct sockaddr * uaddr,
						   int addr_len, int flags);
extern int			inet_recvmsg(struct u_socket *sock, 
					     struct msghdr *ubuf, 
					     int size, int flags, struct u_scm_cookie *scm);
extern int			inet_sendmsg(struct u_socket *sock, 
					     struct msghdr *msg, 
					     int size, struct u_scm_cookie *scm);
extern int			inet_shutdown(struct u_socket *sock, int how);
extern unsigned int		inet_poll(struct u_file * file, struct u_socket *sock, struct u_poll_table_struct *wait);
extern int			inet_setsockopt(struct u_socket *sock, int level,
						int optname, char *optval, 
						int optlen);
extern int			inet_getsockopt(struct u_socket *sock, int level,
						int optname, char *optval, 
						int *optlen);
extern int			inet_fcntl(struct u_socket *sock, 
					   unsigned int cmd, 
					   unsigned long arg);

extern void			inet_sock_release(struct u_sock *sk);
extern void			inet_sock_destruct(struct u_sock *sk);

// just one upcall!  :-) -- XXX don't use 2nd & 3rd args, as we ignore them.
int ip_rcv(struct u_sk_buff *skb, void *dev, void *pt);

#endif /* __USER_TCP_H */
